package cn.tedu.em.passport.service.impl;

import cn.tedu.em.common.pojo.passport.dto.AdminAddNewDTO;
import cn.tedu.em.common.pojo.passport.dto.AdminLoginInfoDTO;
import cn.tedu.em.common.pojo.passport.entity.Admin;
import cn.tedu.em.common.pojo.passport.entity.AdminRole;
import cn.tedu.em.common.pojo.passport.vo.AdminListItemVO;
import cn.tedu.em.common.pojo.passport.vo.AdminStandardVO;
import cn.tedu.em.passport.ex.ServiceException;
import cn.tedu.em.passport.mapper.AdminMapper;
import cn.tedu.em.passport.mapper.AdminRoleMapper;
import cn.tedu.em.passport.security.AdminDetails;
import cn.tedu.em.passport.service.IAdminService;
import cn.tedu.em.passport.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;

@Slf4j
@Service
public class AdminServiceImpl implements IAdminService {

    @Value("${em.jwt.secret-key}")
    private String secretKey;
    @Value("${em.jwt.duration-in-minute}")
    private Long durationInMinute;

    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    AdminMapper adminMapper;
    @Autowired
    AdminRoleMapper adminRoleMapper;
    @Autowired
    private AuthenticationManager authenticationManager;

    public AdminServiceImpl(){
        log.debug("创建业务类对象: AdminServiceImpl");
    }

    @Override
    public String login(AdminLoginInfoDTO adminLoginInfoDTO) {
        log.debug("开始处理【管理员登录】的业务, 参数: {}",adminLoginInfoDTO);
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                adminLoginInfoDTO.getUsername(),adminLoginInfoDTO.getPassword()
        );
        Authentication authenticateResult = authenticationManager.authenticate(authentication);
        log.debug("认证通过!(如果未通过,过程中抛出异常,你不会看到此条日志!)");
        log.debug("认证结果: {}", authenticateResult);
        log.debug("认证结果中的当事人: {}", authenticateResult.getPrincipal());

        // SecurityContext securityContext = SecurityContextHolder.getContext();
        // securityContext.setAuthentication(authenticateResult);

        AdminDetails adminDetails = (AdminDetails) authenticateResult.getPrincipal();
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", adminDetails.getId());
        claims.put("username", adminDetails.getUsername());
        String authoritiesJsonString = JSON.toJSONString(adminDetails.getAuthorities());
        claims.put("authoritiesJsonString", authoritiesJsonString);

        String jwt = Jwts.builder()
                //Header: 声明算法与Token类型
                .setHeaderParam("alg","HS256")
                .setHeaderParam("typ","JWT")
                // Payload：数据，具体表现为Claims
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + durationInMinute * 60 * 1000))
                // Verify Signature：验证签名
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
        log.debug("生成了JWT数据: {}", jwt);
        return jwt;
    }

    @Override
    public void addNew(AdminAddNewDTO adminAddNewDTO) {
        // 从参数对象中获取管理员的用户名
        String username = adminAddNewDTO.getUsername();
        // 调用Mapper对象的countByUsername()执行统计
        int countByName = adminMapper.countByName(username);
        // 判断统计结果是否大于0
        if (countByName > 0){
            // 是：抛出异常
            String message = "用户名已存在!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_CONFLICT,message);
        }
        // 参考以上做法，检查手机号码是否被占用
        String phone = adminAddNewDTO.getPhone();
        int countByPhone = adminMapper.countByPhone(phone);
        if (countByPhone > 0){
            String message = "手机号已被占用!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_CONFLICT,message);
        }
        // 参考以上做法，检查电子邮箱是否被占用
        String email = adminAddNewDTO.getEmail();
        int countByEmail = adminMapper.countByEmail(email);
        if (countByEmail > 0){
            String message = "邮箱已被占用!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_CONFLICT,message);
        }
        // 创建Admin对象
        Admin admin = new Admin();
        // 复制属性
        BeanUtils.copyProperties(adminAddNewDTO,admin);
        // 补全Admin对象的属性值：lastLoginIP(null) / loginCount(0) / gmtLastLogin(null)
        admin.setLoginCount(0);
        // 从Admin对象中取出原密码，执行加密，再将密文存入到Admin对象中
        String rawPassword = admin.getPassword();
        String encodedPassword = passwordEncoder.encode(rawPassword);
        admin.setPassword(encodedPassword);
        // 调用Mapper对象的insert()执行插入
        int rows = adminMapper.insert(admin);
        if (rows != 1){
            String message = "添加管理员失败,服务器忙,请稍后再尝试!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_INSERT,message);
        }
        Long[] roleIds = adminAddNewDTO.getRoleIds();
        List<AdminRole> adminRoleList = new ArrayList<>();
        for (Long roleId : roleIds) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleId);
            adminRoleList.add(adminRole);
        }
        rows = adminRoleMapper.insertBatch(adminRoleList);
        if (rows < 1){
            String message = "添加管理员失败,服务器忙,请稍后再尝试!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_INSERT,message);
        }
    }

    @Override
    public void delete(Long id) {
        log.debug("开始处理【根据ID删除管理员】的业务,参数: {}",id);
        if (id == 1){
            String message = "删除管理员失败，尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }

        AdminStandardVO admin = adminMapper.getStandardById(id);
        log.debug("根据ID={}检查管理员数据是否存在,查询结果: {}",id,admin);
        if (admin == null){
            String message = "尝试删除的管理员数据不存在!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND,message);
        }
        int rows = adminMapper.deleteById(id);
        if (rows != 1){
            String message = "删除管理员失败,服务器忙,请稍后再尝试!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_DELETE,message);
        }

        rows = adminRoleMapper.deleteByAdminId(id);
        if (rows < 1){
            String message = "删除管理员失败,服务器忙,请稍后再尝试!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_DELETE,message);
        }
    }

    @Override
    public void setEnable(Long id) {
        updateEnableById(id,1);
    }

    @Override
    public void setDisable(Long id) {
        updateEnableById(id,0);
    }

    @Override
    public AdminStandardVO getStandardById(Long id) {
        log.debug("开始处理【根据ID查询管理员详情】的业务,参数: {}",id);
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if (queryResult == null){
            String message = "查询失败!管理员数据不存在";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND,message);
        }
        return queryResult;
    }

    @Override
    public List<AdminListItemVO> list() {
        log.debug("开始处理【管理员列表】的业务,无参数");
        List<AdminListItemVO> list = adminMapper.list();
        Iterator<AdminListItemVO> iterator = list.listIterator();
        while (iterator.hasNext()){
            AdminListItemVO item = iterator.next();
            if (item.getId() == 1){
                iterator.remove();
                break;
            }
        }
        return list;
    }

    private void updateEnableById(Long id,Integer enable){
        if (id == 1){
            String message = ENABLE_TEXT[enable] + "管理员失败，尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }
        // 调用Mapper对象的getStandardById()方法执行查询
        AdminStandardVO currentAdmin = adminMapper.getStandardById(id);
        // 判断查询结果是否为null，如果是，则抛出异常
        if (currentAdmin == null) {
            // String message = s[enable] + "失败，…………";
            String message = ENABLE_TEXT[enable] + "失败,数据不存在!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND,message);
        }
        // 判断查询结果中的enable与参数enable是否相同，如果是，则抛出异常（当前状态与目标状态相同，没必要执行更新）
        if (enable.equals(currentAdmin.getEnable())){
            String message = ENABLE_TEXT[enable] + "失败,已经是"+ ENABLE_TEXT[enable] +"状态!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_CONFLICT,message);
        }
        // 创建Category对象
        Admin admin = new Admin();
        // 向Category对象中封装属性值：id, enable，均来自方法参数
        admin.setId(id);
        admin.setEnable(enable);
        // 调用Mapper对象的update()方法执行更新
        int rows = adminMapper.update(admin);
        if (rows != 1){
            String message = ENABLE_TEXT[enable] + "失败,服务器忙,请稍后再尝试!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_UPDATE,message);
        }
    }

}
